package fragmentAppl;

import java.util.ArrayList;

import main.ProcessFinder;

import components.QuasiComponentBehavior;

import impl.Message;
import tools.Debug;
import tools.Fragment;
import tools.FragmentDirectory;
import tools.FragmentState;
import tools.MMME;
import tools.MMMEDirectory;
import visualisation.CompositionView;





public class Behavior extends QuasiComponentBehavior {

	private MMMEDirectory allMMME;
	private Fragment myself; 
	private FragmentDirectory fragDir;
	private boolean init=true;
	private FragmentState previousState;
	
	private boolean alreadyChallenger=false;
	
	public Behavior(MMMEDirectory _allMMME, FragmentDirectory _fragDir){
		//Debug.println("behavior");
		fragDir=_fragDir;
		allMMME=_allMMME;
		previousState=FragmentState.Error;
	}
	

	@Override
	public void cycle(Message msg) { 
		if(init){
			initRep();
			myself=new Fragment(getRequiredMMME(),getProvidedMMME(),getId().toString(),getMyState(),1,0);
			fragDir.addFragment(myself);
			allMMME.addMMME(getProvidedMMME());
			allMMME.addMMME(getRequiredMMME());
			allMMME.addUserMMME(myself, getRequiredMMME(), getProvidedMMME());
			init=false;
			Debug.println(getId().toString()+" : init ok");
		}
	//	Debug.println(getId().toString()+" : perceive");
		perceiveMMME();
	//	Debug.println(getId().toString()+" : decide");
		previousState= getMyState();
		
		FragmentState decision= decide();
		if (decision!=previousState){
			setMyState(decision);
			Debug.println(getId().toString()+" : act "+ getMyState().toString());
			act();	
		}
		allMMME.changeMMMEsState();
	//	allMMME.showMMMEDirectory();
		
	}

	@Override
	public void perceiveMMME() {
		// TODO Auto-generated method stub
		ArrayList<MMME> requiredMMME= new ArrayList<MMME>(getRequiredMMME());
		ArrayList<MMME> providedMMME= new ArrayList<MMME>(getProvidedMMME());
		
		for (int i=0; i<requiredMMME.size();i++)
			setRequiredMMMECharacteristics(allMMME.getMMME(requiredMMME.get(i)));
		for (int i=0; i<providedMMME.size();i++)
			setProvidedMMMECharacteristics(allMMME.getMMME(providedMMME.get(i)));
	}

	@Override
	public FragmentState decide() {
		FragmentState currentState=getMyState();
		if (currentState==FragmentState.Referenced){
			if(getRequiredMMME().size()==0|| getRequiredMMME()==null){
				return FragmentState.Satisfied;
			}
			else{
				if(allrequiredMMMEareProducible(getRequiredMMMECharacteristics()))
					return FragmentState.Satisfied;
				else
					return FragmentState.NoSatisfiedPreconditions;
			}
		}
		if (currentState==FragmentState.Satisfied){
			if(oneOfProvidedMMMEisIncorporated(getProvidedMMMECharacteristics()))
				return FragmentState.Included;
		}
		if (currentState==FragmentState.Included){
			if(oneOfProvidedMMMEisRedundant(getProvidedMMMECharacteristics()))
				return FragmentState.Challenger;
//			if(oneOfProvidedMMMEisConcurent(getProvidedMMMECharacteristics()))
//				return FragmentState.Concurrency;
		}
		if (currentState==FragmentState.NoSatisfiedPreconditions){
			if(oneOfProvidedMMMEisRedundant(getProvidedMMMECharacteristics()))
				return FragmentState.Challenger;
			if(allrequiredMMMEareProducible(getRequiredMMMECharacteristics()))
				return FragmentState.Satisfied;
			else
				return FragmentState.NoSatisfiedPreconditions;
		}
		if (currentState==FragmentState.Challenger){
			if (oneOfProvidedMMMEisRedundant(getProvidedMMMECharacteristics()))
				return FragmentState.Challenger;
			else 
				return FragmentState.Included;
//			setProcessNumber(allMMME.getChallenger(myself));
//			Debug.println(getId()+ " challenger : my process "+getProcessNumber());
//			return FragmentState.Included;			
		}
		if (currentState==FragmentState.Concurrency){
			
		}
		return currentState;
	}


	@Override
	public synchronized void act() {
		// TODO Auto-generated method stub
		FragmentState currentState=getMyState();
		if (currentState==FragmentState.Referenced){
			allMMME.stimuleMMME(myself, getRequiredMMMECharacteristics());
		}
		if (currentState==FragmentState.Satisfied){
			// do nothing
		}
		if (currentState==FragmentState.Included){
			if(getProcessNumber()==0)
				setProcessNumber(allMMME.getNumberOfProcess(getProvidedMMMECharacteristics()));
			if(!alreadyChallenger){
				int n=getProvidedMMMECharacteristics().get(0).getNumberOfProcess();
				if(n!=getProcessNumber()){
					setProcessNumber(n);
					Debug.println(getId().toString()+" INCLUDED number of process : "+getProcessNumber());
				}
			}
		}
		if (currentState==FragmentState.NoSatisfiedPreconditions){
			setCriticity(1);
			allMMME.stimuleMMME(myself, getRequiredMMMECharacteristics());
		}
		if (currentState==FragmentState.Challenger){
			alreadyChallenger=true;
			setProcessNumber(allMMME.getChallengerProcessNumber(getProvidedMMME(), myself));
		}
		if (currentState==FragmentState.Concurrency){
			//setProcessNumber(allMMME.getConcurrentNumberOfProcess());
			Debug.println(getId().toString()+" : CONCURRENCY "+ getMyState().toString());
		}
		myself.setFragment(currentState, getCriticity(), getProcessNumber());
		myself.setElements(getRequiredMMMECharacteristics(), getProvidedMMMECharacteristics());	
//		allMMME.majMyState(myself);
	}


	@Override
	public void sendChallenger() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void sendConcurrency() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void sendStimulation() {
		// TODO Auto-generated method stub
		
	}


	public void setAllMMME(MMMEDirectory allMMME) {
		this.allMMME = allMMME;
	}


	public MMMEDirectory getAllMMME() {
		return allMMME;
	}


	@Override
	public Fragment myself() {
		// TODO Auto-generated method stub
		return myself;
	}


	
}
